﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using DotNetX;
using RPGX.Server.Network;
using System.Diagnostics;
using RPGX.Data;
using System.Threading;
using RPGXEngine.Debugging;
using RPGXEngine.Object;
using RPGXEngine.World;

namespace RPGX.Server
{
    public class Server
    {
        #region Properties

        public NetworkManager NetworkManager
        {
            get { return _networkManager; }
            set { _networkManager = value; }
        }
        private NetworkManager _networkManager = new NetworkManager();

        public DateTime LastServerHealthCheck
        {
            get { return _lastServerHealthCheck; }
            set { _lastServerHealthCheck = value; }
        }
        private DateTime _lastServerHealthCheck = DateTime.MinValue;

        public DateTime LastActionMessageCheck
        {
            get { return _lastActionMessageCheck; }
            set { _lastActionMessageCheck = value; }
        }
        private DateTime _lastActionMessageCheck = DateTime.MinValue;

        public ServerStatus Status
        {
            get
            {
                return this._status;
            }
            set
            {
                ServerRepository.SetStatus(value);

                this.WriteOutputLine(String.Format("Server {0} - {1}", value.GetDescription(), DateTime.Now));

                this._status = value;
            }
        }
        private ServerStatus _status = ServerStatus.Stopped;

        public Performance Performance
        {
            get { return _performance; }
            set { _performance = value; }
        }
        private Performance _performance = new Performance();

        #endregion

        #region Public Methods

        public bool Init()
        {
            this.Shutdown();

            RPGXServerEntities context = new RPGXServerEntities();

            var health = context.ServerHealths;
            foreach (var h in health)
            {
                context.ServerHealths.DeleteObject(h);
            }

            context.SaveChanges();

            this.Performance.Init();

            this.Status = ServerStatus.Starting;

            this.WriteOutputLine(String.Format("Server Name: {0}", Configuration.GetCurrentServerName()));
            this.WriteOutputLine(String.Format("Server Status: {0}", ServerRepository.GetCurrentServerStatus()));

            this.WriteOutputLine("Loading Network Manager");
            this.NetworkManager.Load("serverdata/settings/network.set", this);

            this.Status = ServerStatus.Started;

            return true;
        }

        public bool Run()
        {
            this.WriteOutputLine(String.Format("Server Running - {0}", DateTime.Now));

            while (true)
            {
                try
                {
                    if (this.Status == ServerStatus.Paused)
                    {
                        this.CheckForSystemResume();
                    }
                    else
                    {
                        this.UpdateSeverHealth();

                        this.DoActionMessages();

                        this.NetworkManager.Update();

                        if (this.Status == ServerStatus.Restarting)
                        {
                            this.DoRestart();
                        }
                        else if (this.Status == ServerStatus.Stopped)
                        {
                            break;
                        }
                    }
                }
                catch (RPGXServerException ex)
                {
                    this.WriteOutputLine(ex.Message);
                }
            }

            return true;
        }

        public bool Shutdown()
        {
            this.Status = ServerStatus.Stopping;

            this.WriteOutputLine("Shutting Down Network Manager");
            this.NetworkManager.UnLoad();

            this.Status = ServerStatus.Stopped;

            return true;
        }

        public bool Stop()
        {
            this.Shutdown();

            return true;
        }

        public bool Pause()
        {
            this.Status = ServerStatus.Pausing;

            this.Status = ServerStatus.Paused;

            return true;
        }

        public bool Restart()
        {
            this.Status = ServerStatus.Restarting;

            return true;
        }

        public bool Resume()
        {
            this.Status = ServerStatus.Started;

            return true;
        }

        public void WriteOutput(string message)
        {
            Debug.Write(message);
        }

        public void WriteOutputLine(string message)
        {
            Debug.WriteLine(message);
        }

        #endregion

        #region Private Methods

        private bool CheckForSystemResume()
        {
            ActionMessageProcessor amp = new ActionMessageProcessor(this);
            amp.CheckForSystemResume();

            return true;
        }

        private bool DoRestart()
        {
            this.Init();

            return true;
        }

        private void UpdateSeverHealth()
        {
            TimeSpan ts = DateTime.Now - this.LastServerHealthCheck;
            int span = Configuration.GetServerHealthInterval();

            if (ts.TotalMilliseconds > span)
            {
                RPGXServerEntities context = new RPGXServerEntities();

                var performanceData = this.Performance.Update(span);

                ServerHealth sh = new ServerHealth();
                sh.DateCreated = DateTime.Now;
                sh.TotalMemory = performanceData.BytesInUse;
                sh.CPUUsage = Convert.ToDecimal(performanceData.CPUUsage);
                sh.NumberOfThreads = performanceData.NumberOfThreads;

                context.ServerHealths.AddObject(sh);
                context.SaveChanges();

                this.LastServerHealthCheck = DateTime.Now;

                this.WriteOutputLine("Outputed Server Health");
            }
        }

        private void DoActionMessages()
        {
            TimeSpan ts = DateTime.Now - this.LastActionMessageCheck;
            int span = Configuration.GetActionMessageInterval();

            if (ts.TotalMilliseconds > span)
            {
                ActionMessageProcessor amp = new ActionMessageProcessor(this);
                int messagesProcessed = amp.Process();

                this.LastActionMessageCheck = DateTime.Now;

                this.WriteOutputLine(String.Format("Processed {0} action message{1}", messagesProcessed, messagesProcessed == 1 ? String.Empty : "s"));
            }
        }

        #endregion
    }
}
